/*
Author: 摘星fy
Editor: SublimeText
  Date: 2023-11-26 23:53:49
    QQ: 273259755
    WX: y273259755
*/

import BrainGraph from './lib-brain-graph.js'

export default class BrainGraphControl extends BrainGraph {
  constructor() {
    super(...arguments)

    const d = this.d

    d.keyMap = {
      9: 'tab',
      13: 'enter',
      27: 'esc',
      32: 'space',
      35: 'end',
      36: 'home',
      37: 'left',
      38: 'top',
      39: 'right',
      40: 'bottom',
      46: 'delete',
      113: 'f2',
      ...(() => {
        const map = {}
        for (let i = 65; i < 65 + 26; i++) {
          map[i] = String.fromCharCode(i).toLowerCase()
        }
        return map
      })()
    }

    d.editor = document.createElement('textarea')
    d.editor.className = 'brain-graph-editor'

    this.initEvents()
  }
  cmd(a) {
    switch (a) {
      case '创建子节点': this.showEditor('child'); break
      case '创建兄弟节点': this.showEditor('sibling'); break
      case '编辑节点': this.showEditor('sibling'); break
    }
  }
  initEvents() {
    const d = this.d
    const canvas = d.canvas
    const setCursor = () => {
      canvas.style.cursor = d.isDragScene || d.nodeCatched ? 'move' : ''
    }

    window.onresize = () => {
      this.d.conf.scale = devicePixelRatio
      this.setCanvas()
      this.render()
    }

    canvas.onwheel = (e) => {
      if (e.ctrlKey) return

      const isUp = e.deltaY > 0
      const per = 100 / devicePixelRatio
      this.each(v => {
        v.y += !isUp ? -per : per
      })
      this.render()
    }

    canvas.onkeyup = () => {
      d.isDragScene = false
      setCursor()
    }

    canvas.onkeydown = (e) => {
      const sKey = d.keyMap[e.keyCode]
      const root = d.stair[0]?.[0]

      d.isDragScene = e.ctrlKey
      setCursor()

      if (e.ctrlKey && e.altKey && e.shiftKey) {

      } else if (e.ctrlKey && e.altKey) {
        switch (sKey) {
          case 'f':
            this.setDirection()
            break
        }

      } else if (e.ctrlKey && e.shiftKey) {
        
      } else if (e.altKey && e.shiftKey) {
        
      } else if (e.ctrlKey) {
        switch (sKey) {
          case 'a':
            d.isHighlight = false
            delete d.curNode
            this.each(v => d.mapSelected[v.id] = v)
            this.render()
            break
          case 'left': this.setDirection('l', 15, 15); break
          case 'top': this.setDirection('t', 15, 15); break
          case 'right': this.setDirection('r', 15, 15); break
          case 'bottom': this.setDirection('b', 15, 15); break
          case 'home': this.setCurNode(root); break
          case 'end': this.setCurNode(d.stair.last()?.last()); break
        }
      }/* else if (e.altKey) {
        
      } else if (e.shiftKey) {
        
      }*/ else {
        switch (sKey) {
          case 'left':
            switch (d.direction) {
              case 'l': this.setCurNode(d.curNode ? d.mapId[d.curNode.pid] || d.curNode : root); break
              case 't': this.setCurNode(d.curNode ? this.getPrev(d.curNode) || d.curNode : root); break
              case 'r': this.setCurNode(d.curNode ? this.getChildren(d.curNode)[0] || d.curNode : root); break
              case 'b': this.setCurNode(d.curNode ? this.getPrev(d.curNode) || d.curNode : root); break
            }
            break
          case 'top':
            switch (d.direction) {
              case 'l': this.setCurNode(d.curNode ? this.getPrev(d.curNode) || d.curNode : root); break
              case 't': this.setCurNode(d.curNode ? d.mapId[d.curNode.pid] || d.curNode : root); break
              case 'r': this.setCurNode(d.curNode ? this.getPrev(d.curNode) || d.curNode : root); break
              case 'b': this.setCurNode(d.curNode ? this.getChildren(d.curNode)[0] || d.curNode : root); break
            }
            break
          case 'right':
            switch (d.direction) {
              case 'l': this.setCurNode(d.curNode ? this.getChildren(d.curNode)[0] || d.curNode : root); break
              case 't': this.setCurNode(d.curNode ? this.getNext(d.curNode) || d.curNode : root); break
              case 'r': this.setCurNode(d.curNode ? d.mapId[d.curNode.pid] || d.curNode : root); break
              case 'b': this.setCurNode(d.curNode ? this.getNext(d.curNode) || d.curNode : root); break
            }
            break
          case 'bottom':
            switch (d.direction) {
              case 'l': this.setCurNode(d.curNode ? this.getNext(d.curNode) || d.curNode : root); break
              case 't': this.setCurNode(d.curNode ? this.getChildren(d.curNode)[0] || d.curNode : root); break
              case 'r': this.setCurNode(d.curNode ? this.getNext(d.curNode) || d.curNode : root); break
              case 'b': this.setCurNode(d.curNode ? d.mapId[d.curNode.pid] || d.curNode : root); break
            }
            break
          case 'home': this.setCurNode(d.curNode ? d.stair[d.curNode.depth][0] : root); break
          case 'end': this.setCurNode(d.curNode ? d.stair[d.curNode.depth].last() : root); break
        }
      }
    }

    canvas.onmousemove = (e) => {
      d.nodeCatched = this.catchNode(e)
      if (d.isMouseDown) return
      setCursor()
    }

    canvas.onmousedown = (e) => {
      const {offsetX: x1, offsetY: y1} = e
      const nodeCatched = this.catchNode(e)
      const pos = canvas.getBoundingClientRect()
      const listOrigin = []
      const translateOrigin = {...d.translate}
      const v = {x: 0, y: 0}

      d.isDragScene = e.ctrlKey
      d.isMouseDown = true
      cancelAnimationFrame(d.timerAni)

      // canvas.style.cursor = d.isDragScene ? 'move' : ''

      if (d.isDragScene) {
        this.each(v => listOrigin.push({v, x: v.x, y: v.y}))
      } else {
        if (nodeCatched) {
          const highlightNodes = this.getHighlightNodes()
          const visited = {}
          const dfs = v => {
            if (visited[v.id]) return
            visited[v.id] = true
            listOrigin.push({v, x: v.x, y: v.y})
            !d.mapClose[v.id] && d.mapPid[v.id]?.forEach(dfs)
          }

          d.isHighlight = highlightNodes.includes(nodeCatched)

          if (highlightNodes.includes(nodeCatched)) {
            // highlightNodes.forEach(v => listOrigin.push({v, x: v.x, y: v.y}))
            dfs(highlightNodes[0])
          } else if (d.mapSelected[nodeCatched.id]) {
            Object.values(d.mapSelected).forEach(dfs)
          } else {
            dfs(nodeCatched)
            this.setCurNode(nodeCatched)
          }
        } else {
          // 框选
          d.mapSelected = {}
          delete d.curNode
        }
      }

      document.onmousemove = (e) => {
        const x2 = e.clientX - pos.left
        const y2 = e.clientY - pos.top
        const disX = x2 - x1
        const disY = y2 - y1

        listOrigin.forEach(v => {
          v.v.x = v.x + disX
          v.v.y = v.y + disY
        })

        if (d.isDragScene) {
          d.translate.x = translateOrigin.x + disX
          d.translate.y = translateOrigin.y + disY
        } else {
          if (nodeCatched) {
            // if (d.mapSelected[nodeCatched.id]) {

            // } else {
              
            // }
          } else {
            // 框选
            const w = Math.abs(disX)
            const h = Math.abs(disY)
            const x = disX > 0 ? x1 : x2
            const y = disY > 0 ? y1 : y2

            d.rec.x = x
            d.rec.y = y
            d.rec.w = w
            d.rec.h = h

            d.mapSelected = {}
            this.each(v => {
              this.coll(v, d.rec) && (d.mapSelected[v.id] = v)
            })
          }
        }

        this.render()

        v.x = e.movementX
        v.y = e.movementY
      }

      document.onmouseup = (e) => {
        const x3 = e.clientX - pos.left
        const y3 = e.clientY - pos.top

        document.onmousemove = null
        document.onmouseup = null
        d.isMouseDown = false
        // d.canvas.style.cursor = ''

        if (Math.abs(x3 - x1) < 2 && Math.abs(y3 - y1) < 2) {
          if (e.ctrlKey) {
            // 路径高亮
            this.pathHighlight(nodeCatched)
          } else {
            d.isHighlight = false

            if (nodeCatched) {
              this.setCurNode(nodeCatched)
              console.log(nodeCatched)

              // const result = []
              // const dfs = (v) => {
              //   result.push(v)
              //   this.getChildren(v).forEach(dfs)
              // }
              // dfs(nodeCatched)
              // console.log(JSON.stringify(result.map((v) => {
              //   return {
              //     id: v.id,
              //     pid: v.pid,
              //     name: v.name,
              //   }
              // })))
            } else {
              const btnCatched = this.catchBtnClose(e)
              if (btnCatched) {
                if (e.altKey) {
                  const isClose = !d.mapClose[btnCatched.id]
                  const dfs = v => {
                    isClose ? (d.mapClose[v.id] = v) : (delete d.mapClose[v.id])
                    d.mapPid[v.id]?.forEach(dfs)
                  }
                  dfs(btnCatched)
                  const target = {x: btnCatched.x, y: btnCatched.y}
                  this.setData()
                  const dis = {
                    x: target.x - btnCatched.x,
                    y: target.y - btnCatched.y,
                  }
                  this.setTranslate(d.root.x + dis.x, d.root.y + dis.y)
                } else {
                  this.toggle(btnCatched)
                }
              } else {
                this.render()
              }
            }
          }
        } else {
          if (d.isDragScene || nodeCatched) {
            // 拖拽节点
            const nodeCatched_ = this.catchNode(e, 'igor')

            if (nodeCatched_) {
              if (d.isHighlight) {
                this.getRoot(nodeCatched).pid = nodeCatched_.id
              } else {
                this.getBranchRoots().forEach(v => {
                  v.pid = nodeCatched_.id
                })
              }
              this.setData()
            } else {
              const loopRender = () => {
                if (Math.abs(v.x) < 1 && Math.abs(v.y) < 1) {
                  d.translate.x = d.root?.x || 0
                  d.translate.y = d.root?.y || 0
                  return
                }

                d.timerAni = requestAnimationFrame(loopRender) 
                v.x *= .95
                v.y *= .95
                listOrigin.forEach((node) => {
                  node.v.x += v.x
                  node.v.y += v.y
                })

                this.render()
              }
              loopRender()
            }
          } else {
            // 框选节点
            d.rec.x = 0
            d.rec.y = 0
            d.rec.w = 0
            d.rec.h = 0
            this.render()
          }
        }

        d.isDragScene = false
      }
    }
  }
}
